/*
 * ArcScript Scripts for Arcemu MMORPG Server
 * Copyright (C) 2008 Arcemu Team
 * Copyright (C) 2007 Moon++ <http://www.moonplusplus.com/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "StdAfx.h"
#include "Setup.h"
#include "Base.h"

/************************************************************************/
/* Raid_SerpentshrineCavern.cpp Script					                        */
/************************************************************************/

#ifdef WIN32
#pragma warning(disable:4146)      //warning C4146: unary minus operator applied to unsigned type, result still unsigned
#endif

#define SP_SCALDING_WATER 37284 //This "dot" is supposed to tick whenever you get in the water, it doesnt tick anymore after u kill lurker.

//------------------------------------
//	-= Hydross the Unstable =-
//------------------------------------
#define CN_HYDROSS_THE_UNSTABLE		21216
#define CN_TAINTED_SPAWN_OF_HYDROSS 22036
#define CN_PURE_SPAWN_OF_HYDROSS	22035

#define WATER_TOMB					38235
#define VILE_SLUDGE					38246
#define MARK_OF_HYDROSS1			38215
#define MARK_OF_HYDROSS2			38216
#define MARK_OF_HYDROSS3			38217
#define MARK_OF_HYDROSS4			38218
#define MARK_OF_HYDROSS5			38231
#define MARK_OF_HYDROSS6			40584

#define MARK_OF_CORRUPTION1			38219
#define MARK_OF_CORRUPTION2			38220
#define MARK_OF_CORRUPTION3			38221
#define MARK_OF_CORRUPTION4			38222
#define MARK_OF_CORRUPTION5			38230
#define MARK_OF_CORRUPTION6			40583

#define HYDROSS_ENRAGE				13048
#define PURIFY_ELEMENTAL			36461

class HydrossTheUnstableAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(HydrossTheUnstableAI);
	SP_AI_Spell spells[2];
	bool m_spellcheck[2];

	HydrossTheUnstableAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		nrspells = 2;

		spells[0].info = dbcSpell.LookupEntry(WATER_TOMB); 
		spells[0].targettype = TARGET_RANDOM_SINGLE;
		spells[0].instant = true;
		spells[0].cooldown = 7;
		spells[0].attackstoptimer = 1000;
		m_spellcheck[0] = false;

		spells[1].info = dbcSpell.LookupEntry(VILE_SLUDGE); 
		spells[1].targettype = TARGET_RANDOM_SINGLE;
		spells[1].instant = true;
		spells[1].cooldown = 15;
		spells[1].attackstoptimer = 1000;
		m_spellcheck[1] = false;

		//frost attack type	
		_unit->GetProto()->AttackType = 4;
		//frost immunity
		_unit->SchoolImmunityList[SCHOOL_FROST] = 1;
	}

	void ResetCastTime()
	{
		for (int i = 0; i < nrspells; i++)
			spells[i].casttime = spells[i].cooldown;
	}

	void OnCombatStart(Unit* mTarget)
	{
		ResetCastTime();
		MarkCount = 0;
		form = false;
		MarkTimer = 10;
		minspell = 0;
		maxspell = 0;
		Enraged = false;
		EnrageTimer = 600;

		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I cannot allow you to interfere!");
		_unit->PlaySoundToSet(11289);

		RegisterAIUpdateEvent(1000);
	}

	void OnCombatStop(Unit *mTarget)
	{
		_unit->SetUInt32Value(UNIT_FIELD_DISPLAYID, 20162);
		_unit->SchoolImmunityList[SCHOOL_FROST] = 1;
		_unit->SchoolImmunityList[SCHOOL_NATURE] = 0;

		_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
		_unit->GetAIInterface()->SetAIState(STATE_IDLE);
		RemoveAIUpdateEvent();
	}

	void OnTargetDied(Unit* mTarget)
	{
		if(_unit->GetHealthPct() > 0)	
		{
			if(!form)
			{
				switch(rand()%2)
				{
				case 0:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "They have forced me to this...");
					_unit->PlaySoundToSet(11291);
					break;

				case 1:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I have no choice.");
					_unit->PlaySoundToSet(11292);
					break;
				}
			}
			else
			{
				switch(rand()%2)
				{
				case 0:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL,  "I will purge you from this place.");
					_unit->PlaySoundToSet(11298);
					break;

				case 1:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "You are no better than they!");
					_unit->PlaySoundToSet(11299);
					break;
				}
			}
		}
	}

	void OnDied(Unit * mKiller)
	{
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "You are the disease, not I.");
		_unit->PlaySoundToSet(11300);

		RemoveAIUpdateEvent();
	}

	void AIUpdate()
	{
		if(!form) //water form
		{
			//Mark of Hydross
			if(MarkCount < 6)
			{
				MarkTimer--;
				if(!MarkTimer)
				{
					uint32 spellid = 0;
					switch(MarkCount)
					{
					case 0:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_HYDROSS1), true);
						break;

					case 1:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_HYDROSS2), true);
						break;

					case 2:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_HYDROSS3), true);
						break;

					case 3:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_HYDROSS4), true);
						break;

					case 4:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_HYDROSS5), true);
						break;

					case 5:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_HYDROSS6), true);
						break;
					}

					MarkCount++;
					MarkTimer = 20;
				}
			}

			//Switch check
			float distx = _unit->GetSpawnX() - _unit->GetPositionX();
			float disty = _unit->GetSpawnY() - _unit->GetPositionY();
			float dist = sqrt( (distx*distx) + (disty*disty) );
			if(dist > 25)
			{
				//switch to poison form
				MarkTimer = 10;
				MarkCount = 0;
				minspell = 1;
				maxspell = 1;
				form = true;
				_unit->SetUInt32Value(UNIT_FIELD_DISPLAYID, 5498);
				_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Aaghh, the poison...");
				_unit->PlaySoundToSet(11297);
				_unit->GetProto()->AttackType = 3;
				_unit->SchoolImmunityList[SCHOOL_FROST] = 0;
				_unit->SchoolImmunityList[SCHOOL_NATURE] = 1;

				//Summon 4 elementals
				Creature * summon;
				float posx = _unit->GetPositionX();
				float posy = _unit->GetPositionY();
				float posz = _unit->GetPositionZ();
				float orientation = _unit->GetOrientation();
				summon = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_TAINTED_SPAWN_OF_HYDROSS, 
					posx+6.93f, posy-11.25f, posz, orientation,
					false, false, 0, 0);
				if(summon) summon->SchoolImmunityList[SCHOOL_NATURE] = 1;
				summon = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_TAINTED_SPAWN_OF_HYDROSS, 
					posx-6.93f, posy+11.25f, posz, orientation,
					false, false, 0, 0);
				if(summon) summon->SchoolImmunityList[SCHOOL_NATURE] = 1;
				summon = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_TAINTED_SPAWN_OF_HYDROSS, 
					posx-12.57f, posy-4.72f, posz, orientation,
					false, false, 0, 0);
				if(summon) summon->SchoolImmunityList[SCHOOL_NATURE] = 1;
				summon = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_TAINTED_SPAWN_OF_HYDROSS, 
					posx+12.57f, posy+4.72f, posz, orientation,
					false, false, 0, 0);
				if(summon) summon->SchoolImmunityList[SCHOOL_NATURE] = 1;
			}
		}
		else //poison form
		{
			//Mark of Corruption
			if(MarkCount < 6)
			{
				MarkTimer--;
				if(!MarkTimer)
				{
					uint32 spellid = 0;
					switch(MarkCount)
					{
					case 0:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_CORRUPTION1), true);
						break;

					case 1:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_CORRUPTION2), true);
						break;

					case 2:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_CORRUPTION3), true);
						break;

					case 3:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_CORRUPTION4), true);
						break;

					case 4:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_CORRUPTION5), true);
						break;

					case 5:
						_unit->CastSpell(_unit, dbcSpell.LookupEntry(MARK_OF_CORRUPTION6), true);
						break;
					}

					MarkCount++;
					MarkTimer = 20;
				}
			}

			//Switch check
			float distx = _unit->GetSpawnX() - _unit->GetPositionX();
			float disty = _unit->GetSpawnY() - _unit->GetPositionY();
			float dist = sqrt( (distx*distx) + (disty*disty) );
			if(dist < 25)
			{
				//switch to water form
				MarkTimer = 10;
				MarkCount = 0;
				minspell = 0;
				maxspell = 0;
				form = false;
				_unit->SetUInt32Value(UNIT_FIELD_DISPLAYID, 20162);
				_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Better, much better.");
				_unit->PlaySoundToSet(11290);
				_unit->GetProto()->AttackType = 4;
				_unit->SchoolImmunityList[SCHOOL_FROST] = 1;
				_unit->SchoolImmunityList[SCHOOL_NATURE] = 0;

				//Summon 4 elementals
				Creature * summon;
				float posx = _unit->GetPositionX();
				float posy = _unit->GetPositionY();
				float posz = _unit->GetPositionZ();
				float orientation = _unit->GetOrientation();
				summon = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_PURE_SPAWN_OF_HYDROSS, 
					posx+6.93f, posy-11.25f, posz, orientation,
					false, false, 0, 0);
				if(summon) summon->SchoolImmunityList[SCHOOL_FROST] = 1;
				summon = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_PURE_SPAWN_OF_HYDROSS, 
					posx-6.93f, posy+11.25f, posz, orientation,
					false, false, 0, 0);
				if(summon) summon->SchoolImmunityList[SCHOOL_FROST] = 1;
				summon = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_PURE_SPAWN_OF_HYDROSS, 
					posx-12.57f, posy-4.72f, posz, orientation,
					false, false, 0, 0);
				if(summon) summon->SchoolImmunityList[SCHOOL_FROST] = 1;
				summon = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_PURE_SPAWN_OF_HYDROSS, 
					posx+12.57f, posy+4.72f, posz, orientation,
					false, false, 0, 0);
				if(summon) summon->SchoolImmunityList[SCHOOL_FROST] = 1;
			}
		}

		//Enrage
		if(!Enraged)
		{
			EnrageTimer--;
			if(!EnrageTimer)
			{
				_unit->CastSpell(_unit, dbcSpell.LookupEntry(HYDROSS_ENRAGE), true);
				Enraged = true;
			}
		}

		float val = (float)RandomFloat(100.0f);
		SpellCast(val);
	}

	void SpellCast(float val)
	{
		if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())
		{
			float comulativeperc = 0;
			Unit *target = NULL;
			for(int i = minspell; i <= maxspell; i++)
			{		
				if(m_spellcheck[i])
				{
					target = _unit->GetAIInterface()->GetNextTarget();
					switch(spells[i].targettype)
					{
					case TARGET_SELF:
					case TARGET_VARIOUS:
						_unit->CastSpell(_unit, spells[i].info, spells[i].instant); break;
					case TARGET_ATTACKING:
						_unit->CastSpell(target, spells[i].info, spells[i].instant);
						break;
					case TARGET_DESTINATION:
						_unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break;
					case TARGET_RANDOM_SINGLE:
					case TARGET_RANDOM_DESTINATION:
						CastSpellOnRandomTarget(i, 0, 0); break;
					}
					spells[i].casttime = spells[i].cooldown;
					m_spellcheck[i] = false;
					return;
				}

				if(spells[i].casttime > 0)
					spells[i].casttime--;
					
				if(!spells[i].casttime)
				{
					_unit->setAttackTimer(spells[i].attackstoptimer, false);
					m_spellcheck[i] = true;
				}
				comulativeperc += spells[i].perctrigger;
			}
		}
	}

	void CastSpellOnRandomTarget(uint32 i, float mindist2cast, float maxdist2cast)
	{
		if (!maxdist2cast) maxdist2cast = 100.0f;

		Unit* RandomTarget = NULL;
		std::vector<Unit*> TargetTable;		/* From M4ksiu - Big THX to Capt who helped me with std stuff to make it simple and fully working <3 */
												/* If anyone wants to use this function, then leave this note!										 */
		for(set<Object*>::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) 
		{ 
			if (isHostile(_unit, (*itr)) && ((*itr)->GetTypeId()== TYPEID_UNIT || (*itr)->GetTypeId() == TYPEID_PLAYER))
			{
				RandomTarget = (Unit*)(*itr);

				if (RandomTarget->isAlive() && _unit->GetDistance2dSq(RandomTarget) >= mindist2cast*mindist2cast && _unit->GetDistance2dSq(RandomTarget) <= maxdist2cast*maxdist2cast)
					TargetTable.push_back(RandomTarget);
			} 
		}

		if (!TargetTable.size())
			return;

		Unit * RTarget = *(TargetTable.begin()+rand()%TargetTable.size());

		if (!RTarget)
			return;

		switch (spells[i].targettype)
		{
		case TARGET_RANDOM_SINGLE:
			_unit->CastSpell(RTarget, spells[i].info, spells[i].instant); break;
		case TARGET_RANDOM_DESTINATION:
			_unit->CastSpellAoF(RTarget->GetPositionX(), RTarget->GetPositionY(), RTarget->GetPositionZ(), spells[i].info, spells[i].instant); break;
		}

		TargetTable.clear();
	}

private:
	int nrspells;
	int minspell;
	int maxspell;
	bool form; //false = water | true = poison
	SpellDesc *spell_water_tomb;
	uint32 MarkTimer;
	uint32 MarkCount;
	bool Enraged;
	uint32 EnrageTimer;
};

//------------------------------------
//	-= The Lurker Below=-
//------------------------------------
#define CN_THE_LURKER_BELOW				21217
#define CN_CN_COILFANG_AMBUSHER			21865
#define CN_CN_COILFANG_GUARDIAN			21873

#define WHIRL							37363
#define GEYSER							37478
#define SPOUT							37433
#define SUBMERGE						37433 // Didn't find the spell id
//#define WATER_BOLT					37138  

class LurkerAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(LurkerAI);
	SP_AI_Spell spells[4];
	bool m_spellcheck[4];

	LurkerAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		// -- Number of spells to add --
		nrspells = 4;

		// --- Initialization ---
		for(int i=0;i<nrspells;i++)
		{
			m_spellcheck[i] = false;
		}
		// ----------------------
		
		// Create basic info for spells here, and play with it later , fill always the info, targettype and if is instant or not! 

		spells[0].info = dbcSpell.LookupEntry(WHIRL);
		spells[0].targettype = TARGET_ATTACKING;
		spells[0].instant = true;
		spells[0].cooldown = 30;
		spells[0].perctrigger = 10.0f;
		spells[0].attackstoptimer = 1000; // 1sec
		m_spellcheck[0] = true;

		spells[1].info = dbcSpell.LookupEntry(GEYSER);
		spells[1].targettype = TARGET_VARIOUS;
		spells[1].instant = true;
		spells[1].cooldown = 10;
		spells[1].perctrigger = 10.0f;
		spells[1].attackstoptimer = 2000; // 2sec

		spells[2].info = dbcSpell.LookupEntry(SPOUT);
		spells[2].targettype = TARGET_ATTACKING;
		spells[2].instant = false;
		spells[2].cooldown = 60;
		spells[2].perctrigger = 5.0f;
		spells[2].attackstoptimer = 2000; // 2sec

		spells[3].info = dbcSpell.LookupEntry(SUBMERGE);
		spells[3].targettype = TARGET_SELF;
		spells[3].instant = true;
		spells[3].cooldown = 120;
		spells[3].perctrigger = 10.0f;
		spells[3].attackstoptimer = 2000; // 2sec
	}

	void OnCombatStart(Unit* mTarget)
	{
		RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME));
	}

	void OnCombatStop(Unit *mTarget)
	{
		_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
		_unit->GetAIInterface()->SetAIState(STATE_IDLE);
	   RemoveAIUpdateEvent();
	}

	void OnDied(Unit * mKiller)
	{
		RemoveAIUpdateEvent();
	}

	void OnTargetDied(Unit* mTarget)
	{

	}

	void AIUpdate()
	{
		float val = (float)RandomFloat(100.0f);
		SpellCast(val);
	}

	void SpellCast(float val)
	{
		if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())
		{
			float comulativeperc = 0;
			Unit *target = NULL;
			for(int i=0;i<nrspells;i++)
			{
				if(!spells[i].perctrigger) continue;
				
				if(m_spellcheck[i])
				{
					target = _unit->GetAIInterface()->GetNextTarget();
					switch(spells[i].targettype)
					{
					case TARGET_SELF:
					case TARGET_VARIOUS:
						_unit->CastSpell(_unit, spells[i].info, spells[i].instant); break;
					case TARGET_ATTACKING:
						_unit->CastSpell(target, spells[i].info, spells[i].instant);
						break;
					case TARGET_DESTINATION:
						_unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break;
					}
					m_spellcheck[i] = false;
					return;
				}

				if(val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger))
				{
					_unit->setAttackTimer(spells[i].attackstoptimer, false);
					m_spellcheck[i] = true;
				}
				comulativeperc += spells[i].perctrigger;
			}
		}
	}

protected:
	int nrspells;
};

//------------------------------------
//	-= Leotheras the Blind =-
//------------------------------------

/* ToDo:
 - Some phase timers
 - Insidious whispers
*/

#define CN_LEOTHERAS_THE_BLIND			21215
#define CN_INNER_DEMON					21857 
#define CN_GREYHEART_SPELLBINDER		21806
#define CN_SHADOW_OF_LEOTHERAS			21875

#define MIND_BLAST						37531
#define WHIRLWINDLEO					40653
#define INSIDIOUS_WHISPER				37676
#define CHAOS_BLAST_ANIMATION			37674
#define CHAOS_BLAST_EFFECT				37675
#define LEO_ENRAGE						41447 //13048
#define LEO_BANISH						37546

uint32 LeotherasEventGreyheartToKill[1000000];

class LeotherasAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(LeotherasAI);
	SP_AI_Spell spells[1];
	bool m_spellcheck[1];

	LeotherasAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		//Insidious Whisper (inner demons) 
		//"We all have our demons..." 
		////Debuff that summons an Inner Demon from up to five raid members. Each Inner Demon can be attacked only by the person it spawned from. If you do not kill your Inner Demon before Leotheras gets back into humanoid form you will become Mind Controlled for 10 minutes and can't get out of it unless killed. Inner Demons take increased damage from arcane, nature, and holy spells.
		spells[0].info = dbcSpell.LookupEntry(INSIDIOUS_WHISPER);
		spells[0].targettype = TARGET_VARIOUS;
		spells[0].instant = true;
		spells[0].perctrigger = 2.0f;
		spells[0].attackstoptimer = 2000;
		m_spellcheck[0] = false;

		info_chaos_blast = dbcSpell.LookupEntry(CHAOS_BLAST_ANIMATION);
		info_whirlwind = dbcSpell.LookupEntry(WHIRLWINDLEO);

		_unit->SetUInt64Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9);
		_unit->GetAIInterface()->SetAllowedToEnterCombat(false);

		LeotherasEventGreyheartToKill[_unit->GetInstanceID()] = 0;

		//check if greyheart spellbinders are alive after map initialization
		TimedEvent * te = TimedEvent::Allocate(this, new CallbackP0<LeotherasAI>(this, &LeotherasAI::FirstCheck), 1, 500, 1);
		sWorld.event_AddEvent(te);
	}

	void FirstCheck()
	{
		//count greyheart spellbinders
		Creature *creature = NULL;
		for(set<Object*>::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) 
		{
			if((*itr)->GetTypeId() == TYPEID_UNIT)
			{
				creature = static_cast<Creature*>((*itr));

				if(creature->GetCreatureInfo() && creature->GetCreatureInfo()->Id == CN_GREYHEART_SPELLBINDER && creature->isAlive())
					LeotherasEventGreyheartToKill[_unit->GetInstanceID()]++;
			}
		}

		//no greyheart spellbinder found, release him
		if(!LeotherasEventGreyheartToKill[_unit->GetInstanceID()])
		{
			//remove banish & blocks
			_unit->RemoveAllAuras();
			_unit->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
			_unit->GetAIInterface()->SetAllowedToEnterCombat(true);
			_unit->GetAIInterface()->m_canMove = true;
			_unit->SetStandState(STANDSTATE_STAND);
		}
	}

	void OnCombatStart(Unit* mTarget)
	{
		if(LeotherasEventGreyheartToKill[_unit->GetInstanceID()] != 0)
			return;

		Phase = 0; //nightelf form
		SwitchTimer = 40+rand()%5; //wowwiki says 45, bosskillers says 40
		WhirlwindTimer = 15;
		mInWhirlwind = false;
		FinalPhaseSubphase = 0;
		FinalPhaseTimer = 0;
		IsMorphing = false;
		Enraged = false;
		EnrageTimer = 599; //10 minutes

		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Finally my banishment ends!");
		_unit->PlaySoundToSet(11312);

		RegisterAIUpdateEvent(1000);
	}

	void OnCombatStop(Unit *mTarget)
	{
		//despawn shadow of leotheras
		Creature *shadow = NULL;
		shadow = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), CN_SHADOW_OF_LEOTHERAS);
		if(shadow)
		{
			shadow->Despawn(0, 0);
		}

		SwitchToHumanForm();
		_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
	  	_unit->GetAIInterface()->SetAIState(STATE_IDLE);
	 	RemoveAIUpdateEvent();
	}

	void OnTargetDied(Unit* mTarget)
	{
		if (_unit->GetHealthPct() > 0)
		{
			if(Phase) //blood elf form
			{
				switch (rand()%3)
				{
				case 0:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Kill! KILL!");
					_unit->PlaySoundToSet(11314);
					break;

				case 1:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "That's right! Yes!");
					_unit->PlaySoundToSet(11315);
					break;

				case 2:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Who's the master now?");
					_unit->PlaySoundToSet(11316);
					break;
				}
			}
			else //demon form
			{
				switch (rand()%3)
				{
				case 0:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I have no equal.");
					_unit->PlaySoundToSet(11306);
					break;
				case 1:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Perish, mortal.");
					_unit->PlaySoundToSet(11307);
					break;
				case 2:
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Yes, YES! Ahahah!");
					_unit->PlaySoundToSet(11308);
					break;
				}
			}
		}
	}

	void OnDied(Unit * mKiller)
	{
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "You cannot kill me! Fools, I'll be back! I'll... aarghh...");
		_unit->PlaySoundToSet(11317);
		RemoveAIUpdateEvent();
	}

	void SwitchToHumanForm()
	{
		_unit->SetUInt32Value(UNIT_FIELD_DISPLAYID, 20514);
		_unit->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, _unit->GetProto()->Item1SlotDisplay);
		_unit->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID_1, _unit->GetProto()->Item2SlotDisplay);
		}

	void SwitchToDemonForm()
	{
		_unit->SetUInt32Value(UNIT_FIELD_DISPLAYID, 20125);
		_unit->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, 0);
		_unit->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID_1, 0);
	}

	void AIUpdate()
	{
		if(Phase == 0 || Phase == 3) //nightelf phase
		{
			if(!IsMorphing)
			{
				//whirlwind
				WhirlwindTimer--;
				if(!WhirlwindTimer)
				{
					if(!mInWhirlwind)
					{
						_unit->CastSpell(_unit, info_whirlwind, true);
						_unit->setAttackTimer(15000, false);
						_unit->GetAIInterface()->ClearHateList(); //reset aggro
						WhirlwindTimer = 15;
						mInWhirlwind = true;
					}
					else
					{
						_unit->GetAIInterface()->ClearHateList(); //reset aggro
						WhirlwindTimer = 15;
						mInWhirlwind = false;
					}
				}

				float val = (float)RandomFloat(100.0f);
				SpellCast(val);
			}

			if(Phase == 0)
			{
				//switch to demon form
				SwitchTimer--;
				if(!SwitchTimer)
				{
					//switch to AGENT_SPELL
					_unit->GetAIInterface()->setCurrentAgent(AGENT_SPELL);
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Be gone trifling elf. I'm in control now");
					_unit->PlaySoundToSet(11304);
					SwitchToDemonForm();
					Phase = 1;
					SwitchTimer = 60; //60 seconds
				}

				//15% Leotheras/Demon split
				//wait until he returns nightelf (blizzlike)
				if(_unit->GetHealthPct() <= 15 && !mInWhirlwind)
					Phase = 3;
			}
			else
			{
				Creature *shadow = NULL;
				switch(FinalPhaseSubphase)
				{
				case 0:
					IsMorphing = true;
					_unit->setAttackTimer(15000, false);
					_unit->SetStandState(STANDSTATE_KNEEL);
					_unit->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9);
					_unit->GetAIInterface()->SetAllowedToEnterCombat(false);
					_unit->GetAIInterface()->m_canMove = false;
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "No... no! What have you done? I am the master! Do you hear me? I am... aaggh! Can't... contain him.");
					_unit->PlaySoundToSet(11313);
					FinalPhaseTimer = 10;
					FinalPhaseSubphase++;
					break;

				case 1:
					FinalPhaseTimer--;
					if(!FinalPhaseTimer)
					{
						_unit->SetStandState(STANDSTATE_STAND);
						shadow = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_SHADOW_OF_LEOTHERAS, _unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), _unit->GetOrientation(), true, false, 0, 0); 
						FinalPhaseTimer = 5;
						FinalPhaseSubphase++;
					}
					break;

				case 2:
					FinalPhaseTimer--;
					if(!FinalPhaseTimer)
					{
						_unit->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
						_unit->GetAIInterface()->SetAllowedToEnterCombat(true);
						_unit->GetAIInterface()->m_canMove = true;
						IsMorphing = false;
						FinalPhaseSubphase++;
					}
					break;
						
				default:
					break;
				}
			}

			//Enrage
			if(!Enraged)
			{
				EnrageTimer--;
				if(!EnrageTimer)
				{
					_unit->CastSpell(_unit, dbcSpell.LookupEntry(LEO_ENRAGE), true);
					Enraged = true;
				}
			}
		}
		else if(Phase == 1) //demon form
		{
			//Chaos Blast
			if(_unit->GetAIInterface()->GetNextTarget())
			{
				if(_unit->GetCurrentSpell() == NULL)
				{
					if(rand()%2)
					{
						_unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), info_chaos_blast, false);
					}
				}

				//move if needed
				if(_unit->GetAIInterface()->GetNextTarget()->GetDistance2dSq(_unit) >= 400) //20 yards
				{
					_unit->GetAIInterface()->m_moveRun = true;
					_unit->GetAIInterface()->_CalcDestinationAndMove(_unit->GetAIInterface()->GetNextTarget(), 5.0f);
				}
			}

			//switch
			SwitchTimer--;
			if(!SwitchTimer)
			{
				_unit->GetAIInterface()->setCurrentAgent(AGENT_MELEE);
				SwitchToHumanForm();
				Phase = 0;
				WhirlwindTimer = 10+rand()%5;
				SwitchTimer = 40+rand()%5; //wowwiki says 45, bosskillers says 40
				_unit->GetAIInterface()->ClearHateList(); //reset aggro
			}
		}
	}

	void SpellCast(float val)
	{
		if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())
		{
			float comulativeperc = 0;
			Unit *target = NULL;
			for(int i = 0; i < 1; i++)
			{
				if(!spells[i].perctrigger) continue;
				
				if(m_spellcheck[i])
				{
					target = _unit->GetAIInterface()->GetNextTarget();
					switch(spells[i].targettype)
					{
					case TARGET_SELF:
					case TARGET_VARIOUS:
						_unit->CastSpell(_unit, spells[i].info, spells[i].instant); break;
					case TARGET_ATTACKING:
						_unit->CastSpell(target, spells[i].info, spells[i].instant); break;
					case TARGET_DESTINATION:
						_unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break;
					}

					if (spells[i].speech != "")
					{
						_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, spells[i].speech.c_str());
						_unit->PlaySoundToSet(spells[i].soundid); 
					}

				  	m_spellcheck[i] = false;
					return;
				}

				if(val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger))
				{
					_unit->setAttackTimer(spells[i].attackstoptimer, false);
					m_spellcheck[i] = true;
				}
				comulativeperc += spells[i].perctrigger;
			}
		}
	}

protected:
	int nrspells;
	uint32 SwitchTimer;
	uint32 WhirlwindTimer;
	uint32 EnrageTimer;
	bool Enraged;
	bool mInWhirlwind;
	bool IsMorphing;
	uint32 Phase;
	SpellEntry *info_whirlwind;
	SpellEntry *info_chaos_blast;
	uint32 FinalPhaseSubphase;
	uint32 FinalPhaseTimer;
};

class GreyheartSpellbinderAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(GreyheartSpellbinderAI);
	SP_AI_Spell spells[1];
	bool m_spellcheck[1];

	GreyheartSpellbinderAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		nrspells = 1;

		spells[0].info = dbcSpell.LookupEntry(MIND_BLAST);
		spells[0].targettype = TARGET_RANDOM_SINGLE;
		spells[0].instant = true;
		spells[0].perctrigger = 50.0f;
		spells[0].attackstoptimer = 2000;
		m_spellcheck[0] = false;

		Unit* Leotheras = NULL;
		Leotheras = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(376.543f, -438.631f, 29.7083f, CN_LEOTHERAS_THE_BLIND);
		if(Leotheras)
		{
			_unit->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, Leotheras->GetGUID());
			_unit->SetUInt32Value(UNIT_CHANNEL_SPELL, 30166);//wrong
		}
	}

	void OnCombatStart(Unit* mTarget)
	{			
		_unit->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, 0);
		_unit->SetUInt32Value(UNIT_CHANNEL_SPELL, 0);

		RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME));
	}

    void OnCombatStop(Unit *mTarget)
    {
        _unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
        _unit->GetAIInterface()->SetAIState(STATE_IDLE);

        RemoveAIUpdateEvent();
    }

    void AIUpdate()
    {
		float val = (float)RandomFloat(100.0f);
        SpellCast(val);
    }

	void OnDied(Unit * mKiller)
	{
		LeotherasEventGreyheartToKill[_unit->GetInstanceID()]--;

		//start the event
		if(LeotherasEventGreyheartToKill[_unit->GetInstanceID()] == 0)
		{
			Unit* Leotheras = NULL;
			Leotheras = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(376.543f, -438.631f, 29.7083f, CN_LEOTHERAS_THE_BLIND);
			if(Leotheras)
			{
				//remove banish & blocks
				Leotheras->RemoveAllAuras();
				Leotheras->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
				Leotheras->GetAIInterface()->SetAllowedToEnterCombat(true);
				Leotheras->GetAIInterface()->m_canMove = true;
				Leotheras->SetStandState(STANDSTATE_STAND);

				//attack nearest player
				Player *NearestPlayer;
				float NearestDist = 0;
				for(set<Player*>::iterator itr = _unit->GetInRangePlayerSetBegin(); itr != _unit->GetInRangePlayerSetEnd(); ++itr) 
				{
					if(isHostile(_unit, (*itr)) && ((*itr)->GetDistance2dSq(_unit) < NearestDist || !NearestDist))
					{
						NearestDist = (*itr)->GetDistance2dSq(_unit);
						NearestPlayer = (*itr);
					}
				}

				if(NearestPlayer)
					Leotheras->GetAIInterface()->AttackReaction(NearestPlayer, 1, 0);
			}
		}
	}

    void SpellCast(float val)
    {
        if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())
        {
			float comulativeperc = 0;
		    Unit *target = NULL;
			for(int i=0;i<nrspells;i++)
			{
				if(!spells[i].perctrigger) continue;
				
				if(m_spellcheck[i])
				{
					target = _unit->GetAIInterface()->GetNextTarget();
					switch(spells[i].targettype)
					{
						case TARGET_SELF:
						case TARGET_VARIOUS:
							_unit->CastSpell(_unit, spells[i].info, spells[i].instant); break;
						case TARGET_ATTACKING:
							_unit->CastSpell(target, spells[i].info, spells[i].instant); break;
						case TARGET_DESTINATION:
							_unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break;
						case TARGET_RANDOM_SINGLE:
						case TARGET_RANDOM_DESTINATION:
							CastSpellOnRandomTarget(i, 0, 0); break;
					}
					m_spellcheck[i] = false;
					return;
				}

				if(val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger))
				{
					_unit->setAttackTimer(spells[i].attackstoptimer, false);
					m_spellcheck[i] = true;
				}
				comulativeperc += spells[i].perctrigger;
			}
        }
    }

	void CastSpellOnRandomTarget(uint32 i, float mindist2cast, float maxdist2cast)
	{
		if (!maxdist2cast) maxdist2cast = 100.0f;

		Unit* RandomTarget = NULL;
		std::vector<Unit*> TargetTable;		/* From M4ksiu - Big THX to Capt who helped me with std stuff to make it simple and fully working <3 */
												/* If anyone wants to use this function, then leave this note!										 */
		for(set<Object*>::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) 
		{ 
			if (isHostile(_unit, (*itr)) && ((*itr)->GetTypeId()== TYPEID_UNIT || (*itr)->GetTypeId() == TYPEID_PLAYER) && isAttackable(_unit, (*itr)))
			{
				RandomTarget = (Unit*)(*itr);

				if (RandomTarget->isAlive() && _unit->GetDistance2dSq(RandomTarget) >= mindist2cast*mindist2cast && _unit->GetDistance2dSq(RandomTarget) <= maxdist2cast*maxdist2cast)
					TargetTable.push_back(RandomTarget);
			} 
		}

		if (!TargetTable.size())
			return;

		Unit * RTarget = *(TargetTable.begin()+rand()%TargetTable.size());

		if (!RTarget)
			return;

		switch (spells[i].targettype)
		{
		case TARGET_RANDOM_SINGLE:
			_unit->CastSpell(RTarget, spells[i].info, spells[i].instant); break;
		case TARGET_RANDOM_DESTINATION:
			_unit->CastSpellAoF(RTarget->GetPositionX(), RTarget->GetPositionY(), RTarget->GetPositionZ(), spells[i].info, spells[i].instant); break;
		}

		TargetTable.clear();
	}

private:
	int nrspells;
};

class ShadowofLeotherasAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(ShadowofLeotherasAI);

	ShadowofLeotherasAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		info_chaos_blast = dbcSpell.LookupEntry(CHAOS_BLAST_ANIMATION);

		_unit->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9);
		_unit->GetAIInterface()->SetAllowedToEnterCombat(false);

		TimedEvent * te = TimedEvent::Allocate(this, new CallbackP0<ShadowofLeotherasAI>(this, &ShadowofLeotherasAI::Free), 1, 7500, 1);
		sWorld.event_AddEvent(te);
	}

	void Free()
	{
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "At last I am liberated. It has been too long since I have tasted true freedom!");
		_unit->PlaySoundToSet(11309);

		_unit->SetUInt32Value(UNIT_FIELD_FLAGS, 0);
		_unit->GetAIInterface()->SetAllowedToEnterCombat(true);
		_unit->GetAIInterface()->m_canMove = true;
	}

	void OnCombatStart(Unit* mTarget)
	{
		_unit->GetAIInterface()->setCurrentAgent(AGENT_SPELL);
		RegisterAIUpdateEvent(1000);
	}

	void OnCombatStop(Unit* mTarget)
	{
		RemoveAIUpdateEvent();
	}

	void AIUpdate()
	{
		//Chaos Blast
		if(_unit->GetAIInterface()->GetNextTarget())
		{
			if(_unit->GetCurrentSpell() == NULL)
			{
				if(rand()%2)
				{
					_unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), info_chaos_blast, false);
				}
			}

			//move if needed
			if(_unit->GetAIInterface()->GetNextTarget()->GetDistance2dSq(_unit) >= 400) //20 yards
			{
				_unit->GetAIInterface()->m_moveRun = true;
				_unit->GetAIInterface()->_CalcDestinationAndMove(_unit->GetAIInterface()->GetNextTarget(), 5.0f);
			}
		}
	}

protected:
	SpellEntry* info_chaos_blast;
};

//Chaos blast dummy effect
bool ChaosBlast(uint32 i, Spell * pSpell)
{
	/*Unit *target = NULL;
	if(GUID_HIPART(pSpell->m_targets.m_unitTarget) == HIGHGUID_UNIT)
		target = pSpell->u_caster->GetMapMgr()->GetCreature(pSpell->m_targets.m_unitTarget);
	else if (GUID_HIPART(pSpell->m_targets.m_unitTarget) == HIGHGUID_PLAYER)
		target = objmgr.GetPlayer(pSpell->m_targets.m_unitTarget);*/

	pSpell->u_caster->CastSpell(pSpell->m_targets.m_unitTarget, dbcSpell.LookupEntry(CHAOS_BLAST_EFFECT), true);

	return true;
}

//------------------------------------
//	-= Fathom-Lord Karathress =-
//------------------------------------
#define CN_FATHOM_LORD_KARATHRESS		21214
#define CN_FATHOM_GUARD_SHARKKIS		21966
#define CN_FATHOM_GUARD_TIDALVESS		21965
#define CN_FATHOM_LURKER				22119
#define CN_FATHOM_SPOREBAT				22120
#define CN_FATHOM_GUARD_CARIBDIS		21964
#define CN_SEER_OLUM					22820

#define CATACLYSMIC_BOLT				38441
#define BLESSING_OF_THE_TIDES			38449
#define KARATHRESS_ENRAGE				39249

class KarathressAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(KarathressAI);

	KarathressAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		info_cataclysmic_bolt = dbcSpell.LookupEntry(CATACLYSMIC_BOLT);
		AdvisorsLeft = 0;

		//check if advisors are alive after map initialization
		TimedEvent * te = TimedEvent::Allocate(this, new CallbackP0<KarathressAI>(this, &KarathressAI::CheckAdvisors), 1, 500, 1);
		sWorld.event_AddEvent(te);
	}

	void CheckAdvisors()
	{
		Unit *advisor = NULL;

		//Sharkkis
		advisor = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), CN_FATHOM_GUARD_SHARKKIS);
		if(advisor && advisor->isAlive()) AdvisorsLeft++;

		//Tidalvess
		advisor = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), CN_FATHOM_GUARD_TIDALVESS);
		if(advisor && advisor->isAlive()) AdvisorsLeft++;

		//Caribdis
		advisor = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), CN_FATHOM_GUARD_CARIBDIS);
		if(advisor && advisor->isAlive()) AdvisorsLeft++;
	}

	void OnCombatStart(Unit* mTarget)
	{
		CataclysmicBoltTimer = 60;
		EnrageTimer = 600;
		Enraged = false;
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Guards, attention! We have visitors ...");
		_unit->PlaySoundToSet(11277);
		RegisterAIUpdateEvent(1000);
	}

	void OnCombatStop(Unit *mTarget)
	{
		_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
		_unit->GetAIInterface()->SetAIState(STATE_IDLE);
	   RemoveAIUpdateEvent();
	}

	void OnDied(Unit * mKiller)
	{
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Her ... excellency ... awaits!");
		_unit->PlaySoundToSet(11285);
		RemoveAIUpdateEvent();

		//spawn seer olum and despawn him in 3 minutes
		Creature *olum = NULL;
		olum = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_SEER_OLUM, 451.099f, -544.984f, -7.36327f, 0.174533f, true, false, 0, 0);
		if(olum)
			olum->Despawn(180000, 0);
	}

	void OnTargetDied(Unit* mTarget)
	{
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am rid of you.");
		_unit->PlaySoundToSet(11284);
	}

	void AIUpdate()
	{
		//Cataclysmic Bolt
		CataclysmicBoltTimer--;
		if(!CataclysmicBoltTimer)
		{
			//deal half of target life
			Unit *target = _unit->GetAIInterface()->GetNextTarget();
			if(target && target->GetUInt32Value(UNIT_FIELD_MAXHEALTH) > 0)
			{
				info_cataclysmic_bolt->EffectBasePoints[0] = target->GetUInt32Value(UNIT_FIELD_MAXHEALTH)/2;
				_unit->CastSpell(target, info_cataclysmic_bolt, true);
			}

			CataclysmicBoltTimer = 60;
		}

		//Blessing of the Tides
		if(_unit->GetHealthPct() <= 70 && AdvisorsLeft > 0)
		{
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Your overconfidence will be your undoing! Guards, lend me your strength!");
			_unit->PlaySoundToSet(11278);
			_unit->CastSpell(_unit, dbcSpell.LookupEntry(BLESSING_OF_THE_TIDES), true);
			AdvisorsLeft = 0;
		}

		//Enrage
		if(!Enraged)
		{
			EnrageTimer--;
			if(!EnrageTimer)
			{
				_unit->CastSpell(_unit, dbcSpell.LookupEntry(KARATHRESS_ENRAGE), true);
				Enraged = true;
			}
		}
	}

	uint32 AdvisorsLeft;

private:
	SpellEntry *info_cataclysmic_bolt;
	uint32 CataclysmicBoltTimer;
	uint32 EnrageTimer;
	bool Enraged;
};

//Fathom-Guard Sharkkis (Hunter)
#define MULTI_SHOT				29576
#define LEECHING_THROW			29436
#define THE_BEAST_WITHIN		38373

class FathomGuardSharkissAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(FathomGuardSharkissAI);
	FathomGuardSharkissAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(MULTI_SHOT, Target_Current, 10.0f, 0, 0);
		AddSpell(LEECHING_THROW, Target_Current, 10.0f, 0, 0);
		AddSpell(THE_BEAST_WITHIN, Target_Current, 10.0f, 0, 40);
	}

   void OnCombatStart(Unit* pTarget)
   {
	   CurrentPet = NULL;
	   SummonPetTimer = 5;

	   ArcScriptCreatureAI::OnCombatStart(pTarget);
   }

	void OnDied(Unit* pKiller)
	{
		Creature* FLK = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), CN_FATHOM_LORD_KARATHRESS);
		if(FLK)
		{
			FLK->CastSpell(FLK, dbcSpell.LookupEntry(38455), true); //Power of Sharkkis
			FLK->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I am more powerful than ever!");
			FLK->PlaySoundToSet(11280);
			if(static_cast<KarathressAI*>(FLK->GetScript())->AdvisorsLeft > 0)
				static_cast<KarathressAI*>(FLK->GetScript())->AdvisorsLeft--;
		}

		ArcScriptCreatureAI::OnDied(pKiller);
	}

	void AIUpdate()
	{
		//Summon Pet
		if(!CurrentPet || !CurrentPet->isAlive())
		{
			SummonPetTimer--;
			if(!SummonPetTimer)
			{
				switch(rand()%2)
				{
				case 0:
					CurrentPet = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_FATHOM_LURKER, _unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), 0, true, false, 0, 0);
					break;

				case 1:
					CurrentPet = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_FATHOM_SPOREBAT, _unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), 0, true, false, 0, 0);
					break;
				}

				SummonPetTimer = 5;
			}
		}

		ArcScriptCreatureAI::AIUpdate();
	}

private:
	uint32 SummonPetTimer;
	Creature *CurrentPet;
};

//Fathom-Guard Tidalvess (Shaman)
#define SPITFIRE_TOTEM			38236
#define POISON_CLEANSING_TOTEM	38306
#define EARTHBIND_TOTEM			38304
#define FROST_SHOCK				38234
#define WINDFURY				38229

class FathomGuardTidalvessAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(FathomGuardTidalvessAI);
	FathomGuardTidalvessAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		//totems
		AddSpell(SPITFIRE_TOTEM, Target_Self, 10.0f, 0, 0);
		AddSpell(POISON_CLEANSING_TOTEM, Target_Self, 10.0f, 0, 0);
		AddSpell(EARTHBIND_TOTEM, Target_Self, 10.0f, 0, 0);

		AddSpell(FROST_SHOCK, Target_Current, 10.0f, 0, 0);
		AddSpell(WINDFURY, Target_Current, 10.0f, 0, 0);
	}

	void OnDied(Unit * pKiller)
	{
		Creature* FLK = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), CN_FATHOM_LORD_KARATHRESS);
		if(FLK)
		{
			FLK->CastSpell(FLK, dbcSpell.LookupEntry(38452), true); //Power of Tidalvess
			FLK->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Go on, kill them! I'll be the better for it!");
			FLK->PlaySoundToSet(11279);
			if(static_cast<KarathressAI*>(FLK->GetScript())->AdvisorsLeft > 0)
				static_cast<KarathressAI*>(FLK->GetScript())->AdvisorsLeft--;
		}
		
		ArcScriptCreatureAI::OnDied(pKiller);
	}
};

//Fathom-Guard Caribdis (Priest)
#define HEAL					33144
#define TIDAL_SURGE				38358
#define SUMMON_CYCLONE			38337

class FathomGuardCaribdisAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(FathomGuardCaribdisAI);
	FathomGuardCaribdisAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(TIDAL_SURGE, Target_Self, 20.0f, 0, 10);
		AddSpell(SUMMON_CYCLONE, Target_Self, 2.0f, 0, 0);
	}

	void OnCombatStart(Unit*pTarget)
	{
		HealingWaveTimer = 15;

		ArcScriptCreatureAI::OnCombatStart(pTarget);
	}

	void AIUpdate()
	{
		/*HealingWaveTimer--;
		if(!HealingWaveTimer)
		{
			vector<Unit*> TargetTable;
			for(set<Object*>::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) 
			{
				if((*itr)->GetTypeId() == TYPEID_UNIT && isFriendly(_unit, (*itr)))
					TargetTable.push_back((Unit*)(*itr));
			}

			HealingWaveTimer = 15;
		}*/

		ArcScriptCreatureAI::AIUpdate();
	}

	void OnDied(Unit * pKiller)
	{
		Creature* FLK = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), CN_FATHOM_LORD_KARATHRESS);
		if(FLK)
		{
			FLK->CastSpell(FLK, dbcSpell.LookupEntry(38451), true); //Power of Caribdis
			FLK->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "More knowledge, more power!");
			FLK->PlaySoundToSet(11281);
			if(static_cast<KarathressAI*>(FLK->GetScript())->AdvisorsLeft > 0)
				static_cast<KarathressAI*>(FLK->GetScript())->AdvisorsLeft--;
		}

		ArcScriptCreatureAI::OnDied(pKiller);
	}

private:
	uint32 HealingWaveTimer;
};

//------------------------------------
//	-= Morogrim Tidewalker =-
//------------------------------------
#define CN_MOROGRIM_TIDEWALKER			21213
#define CN_TIDEWALKER_LURKER			21920 //Murlocks that he spawns after earthquake

#define TIDAL_WAVE						37730
#define WATERY_GRAVE					38049
#define EARTHQUAKE						37764
#define SUMMON_WATER_GLOBULE			37854

class MorogrimAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(MorogrimAI);
	SP_AI_Spell spells[4];
	
	MorogrimAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		spells[0].info = dbcSpell.LookupEntry(TIDAL_WAVE);
		spells[0].instant = true;

		spells[1].info = dbcSpell.LookupEntry(EARTHQUAKE);
		spells[1].instant = true;
		spells[1].cooldown = 40;

		spells[2].info = dbcSpell.LookupEntry(WATERY_GRAVE);
		spells[2].instant = true;
		spells[2].cooldown = 30;

		spells[3].info = dbcSpell.LookupEntry(SUMMON_WATER_GLOBULE);
		spells[3].instant = true;
		spells[3].cooldown = 30;
	}

	void OnCombatStart(Unit* mTarget)
	{
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Flood of the deep, take you!");
		_unit->PlaySoundToSet(11321);

		RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME));

		uint32 t = (uint32)time(NULL);
		for (int i = 1; i < 4; i++)
			spells[i].casttime = t + spells[i].cooldown;
	}

	void OnCombatStop(Unit *mTarget)
	{
		_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
		_unit->GetAIInterface()->SetAIState(STATE_IDLE);

		RemoveAIUpdateEvent();
	}

	void OnDied(Unit * mKiller)
	{
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Great... currents of... Ageon.");
		_unit->PlaySoundToSet(11329);

		RemoveAIUpdateEvent();
	}

	void OnTargetDied(Unit* mTarget)
	{
		if (_unit->GetHealthPct() > 0)	
		{
			int RandomSpeach = rand()%3;
			switch (RandomSpeach)
			{
			case 0:
				_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Only the strong survive.");
				_unit->PlaySoundToSet(11328);
				break;
			case 1:
				_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Struggling only makes it worse.");
				_unit->PlaySoundToSet(11327);
				break;
			case 2:
				_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "It is done!");
				_unit->PlaySoundToSet(11326);
				break;
			}
		}
	}

	void AIUpdate()
	{
		if (_unit->GetAIInterface()->GetNextTarget() != NULL && _unit->GetCurrentSpell() == NULL)
		{
			Unit *target = NULL;
			uint32 t = (uint32)time(NULL);
			target = _unit->GetAIInterface()->GetNextTarget();
			if (t > spells[2].casttime)
			{
				_unit->SendChatMessageAlternateEntry(CN_MOROGRIM_TIDEWALKER, CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, " sends his enemies to their watery graves!");
				_unit->CastSpell(target, spells[2].info, spells[2].instant);

				spells[2].casttime = t + spells[2].cooldown;
				return;
			}
			if (t > spells[1].casttime)
			{
				_unit->SendChatMessageAlternateEntry(17165, CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, "The violent earthquake has alerted nearby Murlocs!");

				int RandomSpeach = rand()%2;
				switch (RandomSpeach)
				{
					case 0:
						_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Destroy them my subjects!");
						_unit->PlaySoundToSet(11323);
						break;
					case 1:
						_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "By the Tides, kill them at once!");
						_unit->PlaySoundToSet(11322);
						break;
				}
				_unit->CastSpell(_unit, spells[1].info, spells[1].instant);

				for (int i = 0; i < 6; i++)
					_unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_TIDEWALKER_LURKER, 370.82f, -723.93f, -13.9f, 0, true, false, 0, 0);

				for (int i = 0; i < 6; i++)
					_unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_TIDEWALKER_LURKER, 527.90f, -721.88f, -7.14f, 0, true, false, 0, 0);

				spells[1].casttime = t + spells[1].cooldown;
				return;
			}
			if (_unit->GetHealthPct() < 25)
			{
				if (t > spells[3].casttime)
				{
					_unit->SendChatMessageAlternateEntry(CN_MOROGRIM_TIDEWALKER, CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, " summons Watery Globules!");

					int RandomSpeach = rand()%2;
					switch (RandomSpeach)
					{
						case 0:
							_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Soon it will be finished.");
							_unit->PlaySoundToSet(11325);
							break;
						case 1:
							_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "There is nowhere to hide!");
							_unit->PlaySoundToSet(11324);
							break;
					}
					_unit->CastSpell(target, spells[3].info, spells[3].instant);
					
					spells[3].casttime = t + spells[3].cooldown;
					return;
				}
			}
			else if (_unit->GetHealthPct() >= 25)
			{
				spells[3].casttime = t + spells[3].cooldown;
			}
			
			float random = RandomFloat(100.0f);
			if (random < 10.0f)
			{
				_unit->CastSpell(target, spells[0].info, spells[0].instant);
			}
		}
	}
};

//CN_TIDEWALKER_LURKER
class TidewalkerLurkerAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(TidewalkerLurkerAI);

	TidewalkerLurkerAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		Unit *target = FindTargetForSpell();
		if (target)
		{
			_unit->GetAIInterface()->AttackReaction(target, 1, 0);
		}
	}

	void OnCombatStop(Unit *mTarget)
	{
		_unit->SafeDelete();
	}

	void OnDied(Unit * mKiller)
	{
		_unit->SafeDelete();
	}
	
	Unit* FindTargetForSpell()
	{
		Unit* target = NULL;
		float distance = 150.0f;

		Unit *pUnit;
		float dist;

		for (std::set<Object*>::iterator itr = _unit->GetInRangeOppFactsSetBegin(); itr != _unit->GetInRangeOppFactsSetEnd(); itr++)
		{
			if((*itr)->GetTypeId() != TYPEID_UNIT && (*itr)->GetTypeId() != TYPEID_PLAYER)
				continue;

			pUnit = static_cast<Unit*>((*itr));

			if(pUnit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FEIGN_DEATH))
				continue;

			if(pUnit->m_invisible)
				continue;
			
			if(!pUnit->isAlive() || _unit == pUnit)
				continue;

			dist = _unit->GetDistance2dSq(pUnit);

			if(dist > distance*distance)
				continue;

			target = pUnit;
			break;
		}

		return target;
	}

};

//------------------------------------
//	-= Lady Vashj =-
//------------------------------------

/* ToDo:
 - Toxic Sporebats
 - Coilfang Strider spawn points
 - Some vashj spells and cooldowns are wrong
 - Right Shield generators coords
*/

#define CN_LADY_VASHJ				21212
#define CN_ENCHANTED_ELEMENTAL		21958
#define CN_COILFANG_STRIDER			22056
#define CN_TAINTED_ELEMENTAL		22009
#define CN_COILFANG_ELITE			22055
#define CN_TOXIC_SPORE_BAT			22140
#define CN_SHIELD_GENERATOR_CHANNEL 19870

#define SHOOT						37770
#define ENTANGLE					38316
#define SPAWN_ELEMENTAL				37053 
#define MULTI_SHOT					29576
#define STATIC_CHARGE				38280
#define FORKED_LIGHTNING			40088
#define VASHJ_SHIELD				38112
#define POISON_SPIT					40078
#define TOXIC_SPORES				38575
#define SHOCK_BLAST					38509

#define WALK 0
#define RUN 256
#define FLY 768

struct Coords
{
	float x;
	float y;
	float z;
	float o;
};

static Coords ElementalSpawnPoints[] = 
{
    {8.3f, -835.3f, 21.9f, 5},
    {53.4f, -835.3f, 21.9f, 4.5f},
    {96.0f, -861.9f, 21.8f, 4},
    {96.0f, -986.4f, 21.4f, 2.5f},
    {54.4f, -1010.6f, 22.0f, 1.8f},
    {9.8f, -1012.0f, 21.7f, 1.4f},
    {-35.0f, -987.6f, 21.5f, 0.8f},
    {-58.9f, -901.6f, 21.5f, 6.0f}
};

static Coords ElementalSpawnPoints2[] =
{
	{16.305f, -867.82f, 41.09f, 0},
	{43.853f, -868.338f, 41.097f, 0},
	{71.55f, -885.12f, 40.87f, 0},
	{70.96f, -962.56f, 41.09f, 0},
	{45.227f, -977.987f, 41.09f, 0},
	{17.35f, -979.27f, 41.01f, 0},
	{-9.89f, -963.63f, 41.09f, 0},
	{-25.37f, -910.266f, 41.09f, 0}
};

static Coords CoilfangEliteSpawnPoints[] =
{
	{14.837f, -949.106f, 41.53f, 0},
	{14.857f, -897.68f, 41.536f, 0},
	{29.79f, -923.35f, 42.9f, 0},
	{44.269f, -948.832f, 41.54f, 0}
};

static float ShieldGeneratorCoords[4][3] =
{
	{49.256f, -902.354f, 42.9769f},
	{9.78695f, -902.882f, 42.9f},
	{10.4122f, -944.613f, 42.8262f},
	{49.687f, -944.406f, 42.7324f}
};

static Coords fly[] = 
{
	{ 29.769f, -866.190f, 43, 0 },
	{ 1.135f, -874.345f, 43, 0 },
	{ -19.719f, -894.950f, 43, 0 },
	{ -27.4222f, -923.572f, 43, 0 },
	{ -19.739f, -951.907f, 43, 0 },
	{ 1.059f, -973.314f, 43, 0 },
	{ 30.071f, -980.424f, 43, 0 },
	{ 58.665f, -973.410f, 43, 0 },
	{ 79.353f, -952.011f, 43, 0 },
	{ 87.552f, -923.175f, 43, 0 },
	{ 79.068f, -894.570f, 43, 0 },
	{ 58.503f, -873.295f, 43, 0 }
};

class EnchantedElementalAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(EnchantedElementalAI);
		
	EnchantedElementalAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		_unit->GetAIInterface()->SetAllowedToEnterCombat(false);

		Unit *Vashj = NULL;
		Vashj = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(29.798161f, -923.358276f, 42.900517f, CN_LADY_VASHJ);
		if(Vashj)
		{
			_unit->GetAIInterface()->SetAIState(STATE_SCRIPTMOVE);
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(1);
		}
	}

	void OnReachWP(uint32 iWaypointId, bool bForwards)
	{
		switch(iWaypointId)
		{
		case 1:
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(2);
			break;

		case 2:
			Unit *Vashj = NULL;
			Vashj = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(29.798161f, -923.358276f, 42.900517f, CN_LADY_VASHJ);
			if(Vashj)
			{
				//Increase Lady Vashj attack by 5%
				Vashj->ModFloatValue(UNIT_FIELD_MINDAMAGE, (Vashj->GetFloatValue(UNIT_FIELD_MINDAMAGE)/100)*5);
				Vashj->ModFloatValue(UNIT_FIELD_MAXDAMAGE, (Vashj->GetFloatValue(UNIT_FIELD_MAXDAMAGE)/100)*5);
			}

			//despawn
			_unit->Despawn(0, 0);
			break;
		}
	}
};

class VashjAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(VashjAI);
	SP_AI_Spell spells[4];
	bool m_spellcheck[4];
		
	VashjAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		nrspells = 3;

		spells[0].info = dbcSpell.LookupEntry(SHOCK_BLAST);
		spells[0].targettype = TARGET_ATTACKING;
		spells[0].instant = true;
		spells[0].cooldown = 5;
		spells[0].perctrigger = 5.0f;
		spells[0].attackstoptimer = 2000;
		m_spellcheck[0] = false;

		spells[1].info = dbcSpell.LookupEntry(STATIC_CHARGE);
		spells[1].targettype = TARGET_RANDOM_SINGLE;
		spells[1].instant = true;
		spells[1].cooldown = 5;
		spells[1].perctrigger = 10.0f;
		spells[1].attackstoptimer = 1000;
		m_spellcheck[1] = false;

		spells[2].info = dbcSpell.LookupEntry(ENTANGLE);
		spells[2].targettype = TARGET_RANDOM_DESTINATION;
		spells[2].instant = true;
		spells[2].cooldown = 15;
		spells[2].perctrigger = 10.0f;
		spells[2].attackstoptimer = 1000;
		m_spellcheck[2] = false;

		spells[3].info = dbcSpell.LookupEntry(FORKED_LIGHTNING);
		spells[3].targettype = TARGET_RANDOM_SINGLE;
		spells[3].perctrigger = 0.0f;
		spells[3].instant = false;

		info_multishot = dbcSpell.LookupEntry(MULTI_SHOT);
		info_shot = dbcSpell.LookupEntry(SHOOT);

		WayPoint * wp = _unit->CreateWaypointStruct();
		wp->id = 1;
		wp->x = 29.798161f;
		wp->y = -923.358276f;
		wp->z = 42.900517f;
		wp->o = 0.0f;
		wp->waittime = 0;
		wp->flags = RUN;
		wp->forwardemoteoneshot = 0;
		wp->forwardemoteid = 0;
		wp->backwardemoteoneshot = 0;
		wp->backwardemoteid = 0;
		wp->forwardskinid = 0;
		wp->backwardskinid = 0;

		_unit->GetAIInterface()->addWayPoint(wp);
		_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_DONTMOVEWP);

		_unit->SetUInt64Value(UNIT_FIELD_FLAGS, 0);
	}

	void ResetCastTime()
	{
		for(int i = 0; i < nrspells; i++)
			spells[i].casttime = spells[i].cooldown;
	}

	void OnCombatStart(Unit* mTarget)
	{
		ResetCastTime();
		Phase = 1;
		EnchantedElementalTimer = 10;
		CoilfangStriderTimer = 60;
		CoilfangEliteTimer = 40;
		TaintedElementalTimer = 50;
		SporebatTimer = 0;
		ForkedLightningTimer = 5;

		switch(rand()%4)
		{
		case 0:
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I'll split you from stem to stern!");
			_unit->PlaySoundToSet(11532);
			break;

		case 1:
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Victory to Lord Illidan!");
			_unit->PlaySoundToSet(11533);
			break;

		case 2:
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "I spit on you, surface filth!");
			_unit->PlaySoundToSet(11534);
			break;

		case 3:
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Death to the outsiders!");
			_unit->PlaySoundToSet(11535);
			break;
		}

		RegisterAIUpdateEvent(1000);
	}
		
	void OnCombatStop(Unit *mTarget)
	{
		//despawn enchanted elemental, tainted elemental, coilfang elite, coilfang strider
		Creature *creature = NULL;
		for(set<Object*>::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) 
		{
			if((*itr)->GetTypeId() == TYPEID_UNIT)
			{
				creature = static_cast<Creature*>((*itr));

				if(creature && creature->GetCreatureInfo() && 
					(creature->GetCreatureInfo()->Id == CN_ENCHANTED_ELEMENTAL || 
					creature->GetCreatureInfo()->Id == CN_TAINTED_ELEMENTAL ||
					creature->GetCreatureInfo()->Id == CN_COILFANG_STRIDER ||
					creature->GetCreatureInfo()->Id == CN_COILFANG_ELITE)
					&& creature->isAlive())
					creature->Despawn(500, 0);
			}
		}

		_unit->SetUInt64Value(UNIT_FIELD_FLAGS, 0);
		_unit->RemoveAura(VASHJ_SHIELD);
		_unit->GetAIInterface()->SetAllowedToEnterCombat(true);
		_unit->GetAIInterface()->m_canMove = true;
		_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
		_unit->GetAIInterface()->SetAIState(STATE_IDLE);
		RemoveAIUpdateEvent();
	}
		
	void OnDied(Unit * mKiller)
	{
		_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Lord Illidan, I... I am... sorry.");
		_unit->PlaySoundToSet(11544);
		RemoveAIUpdateEvent();
	}
		
	void OnTargetDied(Unit* mTarget)
	{
		switch(rand()%2)
		{
		case 0:
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Your time ends now!");
			_unit->PlaySoundToSet(11541);
			break;

		case 1:
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "You have failed!");
			_unit->PlaySoundToSet(11542);
			break;
		}
	}
		
	void AIUpdate()
	{
		switch(Phase)
		{
		case 1:
		case 3:
			PhaseOneAndThree();
			break;
		case 2:
			PhaseTwo();
			break;
		}
	}
		
	void PhaseOneAndThree()
	{
		if(Phase == 3)
		{
			//WRONG
			//sporebats are spawned faster and faster
			/*SporebatTimer++;
			if(SporebatTimer > 10)
			{
				Creature *cre = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_TOXIC_SPORE_BAT,  29.769f, -866.190f, 43, 0, false, false, 0, 0);
				cre->GetAIInterface()->setOutOfCombatRange(1);		
				SporebatTimer = 0;
			}*/
		}
		else
		{
			if(_unit->GetHealthPct() <= 70)
			{
				_unit->RemoveAllAuras();
				_unit->GetAIInterface()->SetAllowedToEnterCombat(false);
				_unit->GetAIInterface()->StopMovement(0);
				_unit->GetAIInterface()->SetAIState(STATE_SCRIPTMOVE);
				_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
				_unit->GetAIInterface()->setWaypointToMove(1);
				_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "The time is now! Leave none standing!");
				_unit->PlaySoundToSet(11539);
				_unit->SetUInt64Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_9);
				_unit->CastSpell(_unit, dbcSpell.LookupEntry(VASHJ_SHIELD), true);
				_unit->GetAIInterface()->setOutOfCombatRange(3000);
				Phase = 2;
			}
		}

		//if nobody is in range, shot or multishot
		bool InRange = false;
		for(set<Object*>::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) 
		{
			if(isHostile(_unit, (*itr)) && _unit->GetDistance2dSq((*itr)) < 100) //10 yards
			{
				InRange = true;
				break;
			}
		}
		if(!InRange)
		{
			Shoot(_unit->GetAIInterface()->GetNextTarget());
		}

		float val = (float)RandomFloat(100.0f);
		SpellCast(val);
	}

	void PhaseTwo()
	{
		//WORKAROUND
		_unit->setAttackTimer(2000, false);

		//Forked Lightning
		ForkedLightningTimer--;
		if(!ForkedLightningTimer)
		{
			CastSpellOnRandomTarget(3, 0, 0);
			ForkedLightningTimer = 2+rand()%6;
		}

		//spawn creatures
		EnchantedElementalTimer--;
		if(!EnchantedElementalTimer)
		{
			uint32 pos = rand()%8;
			Creature *elemental = NULL;
			elemental = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_ENCHANTED_ELEMENTAL, ElementalSpawnPoints[pos].x, ElementalSpawnPoints[pos].y, ElementalSpawnPoints[pos].z, ElementalSpawnPoints[pos].o, false, false, 0, 0);
			if(elemental)
			{
				WayPoint * wp = _unit->CreateWaypointStruct();
				wp->id = 1;
				wp->x = ElementalSpawnPoints2[pos].x;
				wp->y = ElementalSpawnPoints2[pos].y;
				wp->z = ElementalSpawnPoints2[pos].z;
				wp->o = ElementalSpawnPoints2[pos].o;
				wp->waittime = 0;
				wp->flags = WALK;
				wp->forwardemoteoneshot = 0;
				wp->forwardemoteid = 0;
				wp->backwardemoteoneshot = 0;
				wp->backwardemoteid = 0;
				wp->forwardskinid = 0;
				wp->backwardskinid = 0;
				elemental->GetAIInterface()->addWayPoint(wp);

				wp = _unit->CreateWaypointStruct();
				wp->id = 2;
				wp->x = 29.798161f;
				wp->y = -923.358276f;
				wp->z = 42.900517f;
				wp->o = 0.0f;
				wp->o = 0;
				wp->waittime = 0;
				wp->flags = WALK;
				wp->forwardemoteoneshot = 0;
				wp->forwardemoteid = 0;
				wp->backwardemoteoneshot = 0;
				wp->backwardemoteid = 0;
				wp->forwardskinid = 0;
				wp->backwardskinid = 0;
				elemental->GetAIInterface()->addWayPoint(wp);
			}
			EnchantedElementalTimer = 10+rand()%5;
		}
		CoilfangStriderTimer--;
		if(!CoilfangStriderTimer)
		{
			Creature *summoned = NULL;
			summoned = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_COILFANG_STRIDER, -29.761278f, -980.252930f, 41.097122f, 0.0f, false, false, 0, 0);
			if(summoned)
			{
				//attack nearest target
				Unit *nearest = NULL;
				float nearestdist = 0;
				for(set<Object*>::iterator itr = summoned->GetInRangeSetBegin(); itr != summoned->GetInRangeSetEnd(); ++itr) 
				{
					if(((*itr)->GetTypeId() == TYPEID_PLAYER || (*itr)->GetTypeId() == TYPEID_UNIT) && isHostile(summoned, (*itr)) && (summoned->GetDistance2dSq((*itr)) < nearestdist || !nearestdist) )
					{
						nearestdist = summoned->GetDistance2dSq((*itr));
						nearest = static_cast<Unit*>((*itr));
					}
				}
				if(nearest)
					summoned->GetAIInterface()->AttackReaction(nearest, 1, 0);
			}
			CoilfangStriderTimer = 60;
		}
		CoilfangEliteTimer--;
		if(!CoilfangEliteTimer)
		{
			uint32 pos = rand()%4;
			Creature *summoned = NULL;
			summoned = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_COILFANG_ELITE, CoilfangEliteSpawnPoints[pos].x, CoilfangEliteSpawnPoints[pos].y, CoilfangEliteSpawnPoints[pos].z, CoilfangEliteSpawnPoints[pos].o, false, false, 0, 0);
			if(summoned)
			{
				//attack nearest target
				Unit *nearest = NULL;
				float nearestdist = 0;
				for(set<Object*>::iterator itr = summoned->GetInRangeSetBegin(); itr != summoned->GetInRangeSetEnd(); ++itr) 
				{
					if(((*itr)->GetTypeId() == TYPEID_PLAYER || (*itr)->GetTypeId() == TYPEID_UNIT) && isHostile(summoned, (*itr)) && (summoned->GetDistance2dSq((*itr)) < nearestdist || !nearestdist) )
					{
						nearestdist = summoned->GetDistance2dSq((*itr));
						nearest = static_cast<Unit*>((*itr));
					}
				}
				if(nearest)
					summoned->GetAIInterface()->AttackReaction(nearest, 1, 0);
			}
			CoilfangEliteTimer = 45;
		}
		TaintedElementalTimer--;
		if(!TaintedElementalTimer)
		{
			uint32 pos = rand()%8;
			_unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_TAINTED_ELEMENTAL, ElementalSpawnPoints[pos].x, ElementalSpawnPoints[pos].y, ElementalSpawnPoints[pos].z, ElementalSpawnPoints[pos].o, false, false, 0, 0);
			TaintedElementalTimer = 120;
		}

		if(_unit->GetHealthPct() <= 50)
		{
			//despawn enchanted elementals
			Creature *creature = NULL;
			for(set<Object*>::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) 
			{
				if((*itr)->GetTypeId() == TYPEID_UNIT)
				{
					creature = static_cast<Creature*>((*itr));

					if(creature->GetCreatureInfo() && creature->GetCreatureInfo()->Id == CN_ENCHANTED_ELEMENTAL && creature->isAlive())
						creature->Despawn(0, 0);
				}
			}

			_unit->SetUInt64Value(UNIT_FIELD_FLAGS, 0);
			_unit->RemoveAura(VASHJ_SHIELD);
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "You may want to take cover.");
			_unit->PlaySoundToSet(11540);
			_unit->GetAIInterface()->m_canMove = true;
			Phase = 3;
		}
	}

	void Shoot(Unit *target)
	{
        switch(rand()%2)
        {
        case 0:
            //shoot
			_unit->CastSpell(target, info_shot, true);
            break;

        case 1:
            //multishot
            _unit->CastSpell(target, info_multishot, true);
            break;
        }

		switch(rand()%6)
		{
		case 0:
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Straight to the heart!");
			_unit->PlaySoundToSet(11536);
			break;

		case 1:
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Seek your mark!");
			_unit->PlaySoundToSet(11537);
			break;
		}
	}

	void OnReachWP(uint32 iWaypointId, bool bForwards)
	{
		switch(iWaypointId)
		{
		case 1:
			_unit->GetAIInterface()->SetAIState(STATE_SCRIPTIDLE);
			_unit->GetAIInterface()->m_canMove = false;

			//setup shield
			Creature *channel = NULL;
			for(uint8 i = 0; i < 4; i++)
			{
				channel = _unit->GetMapMgr()->GetInterface()->SpawnCreature(CN_SHIELD_GENERATOR_CHANNEL, ShieldGeneratorCoords[i][0],  ShieldGeneratorCoords[i][1],  ShieldGeneratorCoords[i][2], 0, false, false, 0, 0);
				if(channel)
				{
					channel->SetUInt64Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
					channel->GetAIInterface()->m_canMove = false;
					channel->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, _unit->GetGUID());
					channel->SetUInt32Value(UNIT_CHANNEL_SPELL, VASHJ_SHIELD);
				}
			}
			break;
		}
	}

	void SpellCast(float val)
	{
		if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())
		{
			float comulativeperc = 0;
			Unit *target = NULL;
			for(int i=0;i<nrspells;i++)
			{
				if(!spells[i].perctrigger) continue;
					
				if(m_spellcheck[i])
				{
					target = _unit->GetAIInterface()->GetNextTarget();
					switch(spells[i].targettype)
					{
					case TARGET_SELF:
					case TARGET_VARIOUS:
						_unit->CastSpell(_unit, spells[i].info, spells[i].instant); break;
					case TARGET_ATTACKING:
						_unit->CastSpell(target, spells[i].info, spells[i].instant);
						break;
					case TARGET_DESTINATION:
						_unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break;
					case TARGET_RANDOM_SINGLE:
					case TARGET_RANDOM_DESTINATION:
						CastSpellOnRandomTarget(i, 0, 0); break;
					}
					spells[i].casttime = spells[i].cooldown;
					m_spellcheck[i] = false;
					return;
				}

				if(spells[i].casttime > 0)
					spells[i].casttime--;
					
				if(val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger) && !spells[i].casttime)
				{
					_unit->setAttackTimer(spells[i].attackstoptimer, false);
					m_spellcheck[i] = true;
				}
				comulativeperc += spells[i].perctrigger;
			}
		}
	}

	void CastSpellOnRandomTarget(uint32 i, float mindist2cast, float maxdist2cast)
	{
		if (!maxdist2cast) maxdist2cast = 100.0f;

		Unit* RandomTarget = NULL;
		std::vector<Unit*> TargetTable;		/* From M4ksiu - Big THX to Capt who helped me with std stuff to make it simple and fully working <3 */
												/* If anyone wants to use this function, then leave this note!										 */
		for(set<Object*>::iterator itr = _unit->GetInRangeSetBegin(); itr != _unit->GetInRangeSetEnd(); ++itr) 
		{ 
			if (isHostile(_unit, (*itr)) && ((*itr)->GetTypeId()== TYPEID_UNIT || (*itr)->GetTypeId() == TYPEID_PLAYER))
			{
				RandomTarget = (Unit*)(*itr);

				if (RandomTarget->isAlive() && _unit->GetDistance2dSq(RandomTarget) >= mindist2cast*mindist2cast && _unit->GetDistance2dSq(RandomTarget) <= maxdist2cast*maxdist2cast)
					TargetTable.push_back(RandomTarget);
			} 
		}

		if (!TargetTable.size())
			return;

		Unit * RTarget = *(TargetTable.begin()+rand()%TargetTable.size());

		if (!RTarget)
			return;

		switch (spells[i].targettype)
		{
		case TARGET_RANDOM_SINGLE:
			_unit->CastSpell(RTarget, spells[i].info, spells[i].instant); break;
		case TARGET_RANDOM_DESTINATION:
			_unit->CastSpellAoF(RTarget->GetPositionX(), RTarget->GetPositionY(), RTarget->GetPositionZ(), spells[i].info, spells[i].instant); break;
		}

		TargetTable.clear();
	}

	uint32 TaintedElementalTimer;
	uint32 Phase;
		
protected:
	int nrspells;
	uint32 EnchantedElementalTimer;
	uint32 CoilfangStriderTimer;
	uint32 CoilfangEliteTimer;
	uint32 SporebatTimer;
	uint32 ForkedLightningTimer;
	SpellEntry *info_multishot;
	SpellEntry *info_shot;
};

class TaintedElementalAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(TaintedElementalAI);
		
	TaintedElementalAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		spell_poison_spit = new AI_Spell();
		spell_poison_spit->agent = AGENT_SPELL;
		spell_poison_spit->procChance = 0;
		spell_poison_spit->spell = dbcSpell.LookupEntry(POISON_SPIT);
		spell_poison_spit->spellType = STYPE_DAMAGE;
		spell_poison_spit->spell->ai_target_type = TTYPE_SINGLETARGET;
		spell_poison_spit->cooldown = 2000;
		spell_poison_spit->cooldowntime = 0;
		spell_poison_spit->procCount = 0;
		spell_poison_spit->procCounter = 0;
		spell_poison_spit->minrange = 0;
		spell_poison_spit->maxrange = 30;

		_unit->GetAIInterface()->m_canMove = false;
	}

	void OnCombatStart(Unit *mTarget)
	{
		_unit->GetAIInterface()->setCurrentAgent(AGENT_SPELL);
		RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME));
	}

	void OnCombatStop(Unit *mTarget)
	{
		RemoveAIUpdateEvent();
	}

	void OnDied(Unit * mKiller)
	{
		Creature *Vashj = NULL;
		Vashj = _unit->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(_unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), CN_LADY_VASHJ);
		if(Vashj)
		{
			if(static_cast<VashjAI*>(Vashj->GetScript())->TaintedElementalTimer > 50)
				static_cast<VashjAI*>(Vashj->GetScript())->TaintedElementalTimer = 50;
		}
	}

	void AIUpdate()
	{
		//TODO: Despawn after 15 secs
		if(_unit->GetCurrentSpell() == NULL)
			_unit->GetAIInterface()->SetNextSpell(spell_poison_spit);
	}

private:
	AI_Spell *spell_poison_spit;
};

class SCRIPT_DECL TaintedCore : public GossipScript
{
public:
	void GossipHello(Object * pObject, Player* Plr, bool AutoSend)
	{
		//WORKAROUND
		GameObject *shield = Plr->GetMapMgr()->GetInterface()->GetGameObjectNearestCoords(Plr->GetPositionX(), Plr->GetPositionY(), Plr->GetPositionZ(), 185051);
		if(shield && shield->GetDistance2dSq(Plr) < 25)
		{
			//deal 5% life 
			Creature *Vashj = NULL;
			Vashj = Plr->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(29.798161f, -923.358276f, 42.900517f, CN_LADY_VASHJ);
			if(Vashj)
			{
				if(static_cast<VashjAI*>(Vashj->GetScript())->Phase == 2)
				{
					Vashj->ModUnsigned32Value(UNIT_FIELD_HEALTH, -((Vashj->GetUInt32Value(UNIT_FIELD_MAXHEALTH)/100)*5) );

					//despawn channel
					Creature *channel = NULL;
					channel = Plr->GetMapMgr()->GetInterface()->GetCreatureNearestCoords(shield->GetPositionX(), shield->GetPositionY(), shield->GetPositionZ(), CN_SHIELD_GENERATOR_CHANNEL);
					if(channel)
						channel->Despawn(0, 0);

					Plr->GetItemInterface()->RemoveItemAmt(31088, 1);
				}
			}
		}
	}

	void GossipSelectOption(Object * pObject, Player* Plr, uint32 Id, uint32 IntId, const char * Code) { }
	void GossipEnd(Object * pObject, Player* Plr) { GossipScript::GossipEnd(pObject, Plr); }
	void Destroy() { delete this; }
};

class ToxicSporeBatAI : public CreatureAIScript
{
public:
	ADD_CREATURE_FACTORY_FUNCTION(ToxicSporeBatAI);
	SP_AI_Spell spells[1];
	bool m_spellcheck[1];
		
	ToxicSporeBatAI(Creature* pCreature) : CreatureAIScript(pCreature)
	{
		/************************ Waypoint Place ************************/
		
		m_entry = pCreature->GetEntry();
		
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(1, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(2, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(3, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(4, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(5, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(6, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(7, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(8, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(9, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(10, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(11, 0, FLY));
		_unit->GetAIInterface()->addWayPoint(CreateWaypoint(12, 0, FLY));
		
		/************************** Spells ****************************/
		
		nrspells = 1;
		for(int i=0;i<nrspells;i++)
		{
			m_spellcheck[i] = false;
		}
		
		spells[0].info = dbcSpell.LookupEntry(TOXIC_SPORES);
		spells[0].targettype = TARGET_VARIOUS;
		spells[0].instant = true;
		spells[0].cooldown = -1;
		spells[0].perctrigger = 0.0f;
		spells[0].attackstoptimer = 1000;
		
		/******************* Additional Settings *******************/
		
		Phase = 0;
		FlameQuills = false;
		Meteor = false;
		PositionChange=rand()%8+15;
		PhoenixSummon=rand()%6+17;
		_unit->GetAIInterface()->m_moveFly = true;
		_unit->GetAIInterface()->StopMovement(0);
		_unit->GetAIInterface()->SetAIState(STATE_SCRIPTMOVE);
		_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
		_unit->GetAIInterface()->setWaypointToMove(1);
		RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME));
	}
		
	void OnCombatStart(Unit* mTarget)
	{
		//_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Phase 1 Test!");
		_unit->PlaySoundToSet(11243);
		_unit->GetAIInterface()->SetAIState(STATE_SCRIPTIDLE);
		_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_DONTMOVEWP);
		CastTime();
		Phase = 1;
		FlameQuills = false;
		Meteor = false;
		PositionChange=rand()%8+15;	// 30-45sec /*** if attack time 1000 (%15+31) ***/
		PhoenixSummon=rand()%6+17;	// 34-44sec /*** if attack time 1000 (%11+34) ***/
		FlyWay=rand()%2;
		switch (FlyWay)
		{
		case 0:	// Clock like
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(6);
			break;
				
		case 1:	// hmm... other?
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(9);
			break;
		}
		//RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME));	// Taken from here to add more abilities to code
	}
		
	void CastTime()
	{
		for(int i=0;i<nrspells;i++)
			spells[i].casttime = spells[i].cooldown;
	}
		
	void OnCombatStop(Unit *mTarget)
	{
		Phase = 0;
		FlameQuills = false;
		Meteor = false;
		PhoenixSummon=rand()%6+17;
		PositionChange=rand()%8+15;
		CastTime();
		_unit->GetAIInterface()->StopMovement(0);
		_unit->GetAIInterface()->SetAIState(STATE_SCRIPTMOVE);
		_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
		_unit->GetAIInterface()->setWaypointToMove(1);
		//_unit->GetAIInterface()->setCurrentAgent(AGENT_NULL);
		//_unit->GetAIInterface()->SetAIState(STATE_IDLE);
		//RemoveAIUpdateEvent();
	}
		
	void OnDied(Unit * mKiller)
	{
		Phase = 0;
		FlameQuills = false;
		Meteor = false;
		PositionChange=rand()%8+15;
		PhoenixSummon=rand()%6+17;
		CastTime();
		//RemoveAIUpdateEvent();
	}
		
	void AIUpdate()
	{
		if (FlameQuills == true)
		{
			QuillsCount++;
			if (QuillsCount == 9)
			{
				FlameQuills = false;
				switch (FlyWay)
				{
				case 0:	// Clock like
					_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
					_unit->GetAIInterface()->setWaypointToMove(6);
					break;
					
				case 1:	// hmm... other?
					_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
					_unit->GetAIInterface()->setWaypointToMove(9);
					break;
				}
			}
			_unit->CastSpell(_unit, spells[1].info, spells[1].instant);
		}
		
		if (Meteor == true)
		{
		}
		else 
		{
			switch (Phase)
			{
				case 0: return;
				case 1: 
				{
				PhaseOne();
				}break;
				case 2:
				{
				PhaseTwo();
				}break;
				default:
				{
				Phase = 0;
				};
			};
		}
		//float val = (float)RandomFloat(100.0f);
		//SpellCast(val);
	}
		
	void PhaseOne()
	{
		PositionChange--;
		PhoenixSummon--;
		
		if (_unit->GetHealthPct() == 0)
		{
			Phase = 2;
			_unit->CastSpell(_unit, spells[6].info, spells[6].instant);
		}
		
		if (!PhoenixSummon--)
		{
			_unit->CastSpell(_unit, spells[2].info, spells[2].instant);
			PhoenixSummon=rand()%6+17;
		}
		
		if (!PositionChange)
		{
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(NextWP);
			PositionChange=rand()%8+17;	// added 4 sec fit time + time needed to move to next pos.
		}
		
		else
		{
			uint32 val = RandomUInt(100);
			
			if (val > 0 && val < 5)	// Flame Quills wp here!
			{
				_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
				_unit->GetAIInterface()->setWaypointToMove(10);
			}
		}
	}
		
	void PhaseTwo()
	{
		
	}
		
	void SpellCast(float val)
	{
		if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())
		{
			float comulativeperc = 0;
			Unit *target = NULL;
			for(int i=0;i<nrspells;i++)
			{
				spells[i].casttime--;
				
				if (m_spellcheck[i])
				{				
				spells[i].casttime = spells[i].cooldown;
				target = _unit->GetAIInterface()->GetNextTarget();
				switch(spells[i].targettype)
				{
					case TARGET_SELF:
					case TARGET_VARIOUS:
						_unit->CastSpell(_unit, spells[i].info, spells[i].instant); break;
					case TARGET_ATTACKING:
						_unit->CastSpell(target, spells[i].info, spells[i].instant); break;
					case TARGET_DESTINATION:
						_unit->CastSpellAoF(target->GetPositionX(),target->GetPositionY(),target->GetPositionZ(), spells[i].info, spells[i].instant); break;
				}
				
				if (spells[i].speech != "")
				{
					_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, spells[i].speech.c_str());
					_unit->PlaySoundToSet(spells[i].soundid); 
				}
				
				m_spellcheck[i] = false;
				return;
				}
				
				if ((val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger)) || !spells[i].casttime)
				{
				_unit->setAttackTimer(spells[i].attackstoptimer, false);
				m_spellcheck[i] = true;
				}
				comulativeperc += spells[i].perctrigger;
			}
		}
	}
		
	void OnReachWP(uint32 iWaypointId, bool bForwards)
	{
		if (Phase == 1)
		{
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(6);
			_unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Phase 1 Test!");
			_unit->PlaySoundToSet(11243);
		}
		
		switch(iWaypointId)
		{
		case 1:	// First fly point
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(2);
			break;
				
		case 2:
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(3);
			break;
				
		case 3:
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(4);
			break;
				
		case 4:
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(5);
			break;
				
		case 5:
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
			_unit->GetAIInterface()->setWaypointToMove(1);	// Last fly point (flyback to point 1 - reset)
			break;
				
		case 6:
		{
			_unit->GetAIInterface()->SetAIState(STATE_SCRIPTIDLE);
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_DONTMOVEWP);
			_unit->GetAIInterface()->m_canMove = false;
			switch (FlyWay)
			{
			case 0:
				NextWP = 7;
				break;
					
			case 1:	
				NextWP = 9;
				break;
			}
		}
			break;
				
		case 7:
		{
			_unit->GetAIInterface()->SetAIState(STATE_SCRIPTIDLE);
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_DONTMOVEWP);
			_unit->GetAIInterface()->m_canMove = false;
			switch (FlyWay)
			{
			case 0:
				NextWP = 8;
				break;
					
			case 1:	
				NextWP = 6;
				break;
			}
		}
			break;
				
		case 8:
		{
			_unit->GetAIInterface()->m_canMove = false;
			_unit->GetAIInterface()->SetAIState(STATE_SCRIPTIDLE);
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_DONTMOVEWP);
			switch (FlyWay)
			{
			case 0:
				NextWP = 9;
				break;
					
			case 1:
				NextWP = 7;
				break;
			}
		}
			break;
				
		case 9:
		{
			_unit->GetAIInterface()->m_canMove = false;
			_unit->GetAIInterface()->SetAIState(STATE_SCRIPTIDLE);
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_DONTMOVEWP);
			switch (FlyWay)
			{
			case 0:
				NextWP = 6;
				break;

			case 1:	
				NextWP = 8;
				break;
			}
		}
			break;
				
		case 10:
		{
			_unit->GetAIInterface()->SetAIState(STATE_SCRIPTIDLE);
			_unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_DONTMOVEWP);
			if (Phase == 1)
			{
				FlameQuills = true;
				QuillsCount = 0;
			}
				
			if (Phase == 2)
			{
				Meteor = true;
			}
				
		}
			break;
		}
	}
		
	inline WayPoint* CreateWaypoint(int id, uint32 waittime, uint32 flags)
	{
		WayPoint * wp = _unit->CreateWaypointStruct();
		wp->id = id;
		wp->x = fly[id].x;
		wp->y = fly[id].y;
		wp->z = fly[id].z;
		wp->o = fly[id].o;
		wp->waittime = waittime;
		wp->flags = flags;
		wp->forwardemoteoneshot = 0;
		wp->forwardemoteid = 0;
		wp->backwardemoteoneshot = 0;
		wp->backwardemoteid = 0;
		wp->forwardskinid = 0;
		wp->backwardskinid = 0;
		return wp;
	}
		
protected:
	bool FlameQuills;
	uint32 QuillsCount;
	bool Meteor;
	int PositionChange;
	int PhoenixSummon;
	uint32 NextWP;
	uint32 m_entry;
	uint32 FlyWay;
	uint32 Phase;
	int nrspells;
};


//------------------------------------
//	-= Trash Mobs =-
//------------------------------------
	
//Coilfang Ambusher
#define CN_COILFANG_AMBUSHER		21865
#define CA_MULTI_SHOT				27021

class CoilfangAmbusherAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(CoilfangAmbusherAI);
	CoilfangAmbusherAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(CA_MULTI_SHOT, Target_Self, 10.0f, 0, 0);
	}
};

//Coilfang Fathom-Witch
#define CN_COILFANG_FATHOM_WITCH	21299
#define SHADOW_BOLT					27209 
#define WHIRLWIND_KNOCKBACK			34109 

class CoilfangFathomWitchAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(CoilfangFathomWitchAI);
	CoilfangFathomWitchAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(SHADOW_BOLT, Target_Current, 2.0f, 0, 0);
		AddSpell(WHIRLWIND_KNOCKBACK, Target_Self, 2.0f, 0, 0);
	}
};

//Coilfang Guardian
#define CN_COILFANG_GUARDIAN		21873
#define CLEAVE						38260

class CoilfangGuardianAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(CoilfangGuardianAI);
	CoilfangGuardianAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(CLEAVE, Target_Destination, 3.0f, 0, 0);
	}
};

//Coilfang Priestess
#define CN_COILFANG_PRIESTESS		21220
#define HOLY_NOVA					38589 
#define SMITE						25364 
#define SPIRIT_OF_REDEMPTION		35618

class CoilfangPriestessAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(CoilfangPriestessAI);
	CoilfangPriestessAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(HOLY_NOVA, Target_Self, 2.0f, 0, 0);
		AddSpell(SMITE, Target_Current, 1.0f, 2, 0);
		AddSpell(SPIRIT_OF_REDEMPTION, Target_Self, 2.0f, 0, 0);
	}
};

//Underbog Colossus 
#define CN_UNDERBOG_COLOSSUS		21251
#define ACID_GEYSER					37959 
#define ATROPIC_BLOW				39015 
#define SPORE_QUAKE					38976
#define TOXIC_POOL					38718
#define FRENZY						37605
#define RAMPANT_INFECTION			39042
#define PARASITE					39044

class UnderbogColossusAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(UnderbogColossusAI);
	UnderbogColossusAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		//these mobs pick from a random set of abilities
		switch(rand()%3)
		{
		case 0:
			AddSpell(RAMPANT_INFECTION, Target_Self, 5.0f, 0, 0);
			AddSpell(SPORE_QUAKE, Target_Self, 2.0f, 0, 0);
			break;

		case 1:
			AddSpell(ACID_GEYSER, Target_Destination, 10.0f, 0, 0);
			AddSpell(PARASITE, Target_Current, 2.0f, 0, 0);
			break;

		case 2:
			AddSpell(FRENZY, Target_Self, 10.0f, 0, 0);
			break;
		}
	}

	void OnDied(Unit* pKiller)
	{
		//There will also be a choice of abilities he might use as he dies:
		switch(rand()%3)
		{
		case 0:
			//cast toxic pool
			_unit->CastSpell(_unit, dbcSpell.LookupEntry(TOXIC_POOL), true);
			break;

		case 1:
			//spawn two colossus lurkers
			_unit->GetMapMgr()->GetInterface()->SpawnCreature(22347, _unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), 0, true, false, 0, 0);
			_unit->GetMapMgr()->GetInterface()->SpawnCreature(22347, _unit->GetPositionX(), _unit->GetPositionY(), _unit->GetPositionZ(), 0, true, false, 0, 0);
			break;

		default:
			//Nothing!
			break;

			//Many small adds, TODO
			//Refreshing mist, TODO
		}

		ArcScriptCreatureAI::OnDied(pKiller);
	}
};

//Tidewalker Warrior
#define CN_TIDEWALKER_WARRIOR		21225
#define TW_CLEAVE					38260 
#define TW_BLOODTHIRST				30335 //INSTANT
#define TW_FRENZY					37605

class TidewalkerWarriorAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(TidewalkerWarriorAI);
	TidewalkerWarriorAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(TW_CLEAVE, Target_Destination, 1.0f, 0, 0);
		AddSpell(TW_BLOODTHIRST, Target_Current, 1.0f, -1, 0); //-1 means instant
		AddSpell(TW_FRENZY, Target_Self, 2.0f, 0, 0);
	}
};

//Coilfang Serpentguard
#define CN_COILFANG_SERPENTGUARD	21298
#define CSERP_CLEAVE				38260 
#define CSERP_REFLECTION			36096 
#define CSERP_DEVOTION				38603 

class CoilfangSerpentguardAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(CoilfangSerpentguardAI);
	CoilfangSerpentguardAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(CSERP_CLEAVE, Target_Destination, 1.0f, 0, 0);
		AddSpell(CSERP_REFLECTION, Target_Self, 0.5f, 0, 0);
		AddSpell(CSERP_DEVOTION, Target_Self, 1.0f, 0, 0);
	}
};

//Coilfang Shatterer
#define CN_COILFANG_SHATTERER		21301
#define CSHATT_ARMOR				38591 

class CoilfangShattererAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(CoilfangShattererAI);
	CoilfangShattererAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(CSHATT_ARMOR, Target_Current, 2.0f, 0, 0);
	}
};

//Coilfang Strider
#define CN_COILFANG_STRIDER			22056
#define CSTRID_SCREAM				10890 

class CoilfangStriderAI : public ArcScriptCreatureAI
{
public:
    ADD_CREATURE_FACTORY_FUNCTION(CoilfangStriderAI);
	CoilfangStriderAI(Creature* pCreature) : ArcScriptCreatureAI(pCreature)
	{
		AddSpell(CSTRID_SCREAM, Target_Current, 2.0f, 0, 0);
	}
};

void SetupSerpentshrineCavern(ScriptMgr * mgr)
{
	mgr->register_creature_script(CN_HYDROSS_THE_UNSTABLE, &HydrossTheUnstableAI::Create);
	mgr->register_creature_script(CN_THE_LURKER_BELOW, &LurkerAI::Create);

	//Leotheras the Blind event
	mgr->register_creature_script(CN_LEOTHERAS_THE_BLIND, &LeotherasAI::Create);
	mgr->register_creature_script(CN_GREYHEART_SPELLBINDER, &GreyheartSpellbinderAI::Create);
	mgr->register_creature_script(CN_SHADOW_OF_LEOTHERAS, &ShadowofLeotherasAI::Create);
	mgr->register_dummy_spell(CHAOS_BLAST_ANIMATION, &ChaosBlast);

	//Morogrim Tidewalker event
	mgr->register_creature_script(CN_MOROGRIM_TIDEWALKER, &MorogrimAI::Create);
	mgr->register_creature_script(CN_TIDEWALKER_LURKER, &TidewalkerLurkerAI::Create);
	
	//Fathom-Lord Karathress event
	mgr->register_creature_script(CN_FATHOM_LORD_KARATHRESS, &KarathressAI::Create);
	mgr->register_creature_script(CN_FATHOM_GUARD_CARIBDIS, &FathomGuardCaribdisAI::Create);
	mgr->register_creature_script(CN_FATHOM_GUARD_TIDALVESS, &FathomGuardTidalvessAI::Create);
	mgr->register_creature_script(CN_FATHOM_GUARD_SHARKKIS, &FathomGuardSharkissAI::Create);

	//Lady Vashj event
	mgr->register_creature_script(CN_LADY_VASHJ, &VashjAI::Create);
	//mgr->register_creature_script(CN_TOXIC_SPORE_BAT, &ToxicSporeBatAI::Create);
	mgr->register_creature_script(CN_COILFANG_STRIDER, &CoilfangStriderAI::Create);
	mgr->register_creature_script(CN_ENCHANTED_ELEMENTAL, &EnchantedElementalAI::Create);
	mgr->register_creature_script(CN_TAINTED_ELEMENTAL, &TaintedElementalAI::Create);
	GossipScript * tc = (GossipScript*) new TaintedCore;
	mgr->register_item_gossip_script(31088, tc);

	//Trash mobs
	mgr->register_creature_script(CN_COILFANG_AMBUSHER, &CoilfangAmbusherAI::Create);
	mgr->register_creature_script(CN_COILFANG_FATHOM_WITCH, &CoilfangFathomWitchAI::Create);
	mgr->register_creature_script(CN_COILFANG_GUARDIAN, &CoilfangGuardianAI::Create);
	mgr->register_creature_script(CN_COILFANG_PRIESTESS, &CoilfangPriestessAI::Create);
	mgr->register_creature_script(CN_UNDERBOG_COLOSSUS, &UnderbogColossusAI::Create);
	mgr->register_creature_script(CN_TIDEWALKER_WARRIOR, &TidewalkerWarriorAI::Create);
	mgr->register_creature_script(CN_COILFANG_SERPENTGUARD, &CoilfangSerpentguardAI::Create);
	mgr->register_creature_script(CN_COILFANG_SHATTERER, &CoilfangShattererAI::Create);
}
